home *** CD-ROM | disk | FTP | other *** search
- /* There are only two functions in this mailbox code that depend on the
- underlying protocol, namely mbx_getname() and dochat(). All the other
- functions can hopefully be used without modification on other stream
- oriented protocols than AX.25 or NET/ROM.
- However, please note that on AX.25 '\r' is used as EOL character while
- on for instance TCP, '\r\n' is used. It would be handy if there were
- a printf-compatible function that would take '\n' and map it to whatever
- is the convention for the particular protocol in use.
- SM0RGV 890506, most work done previously by W9NK
- */
- #include <stdio.h>
- #include <time.h>
- #include <ctype.h>
- #ifdef UNIX
- #include <sys/types.h>
- #endif
- #include "global.h"
- #include "ax_mbx.h"
- #include "cmdparse.h"
- #include "proc.h"
- #include "socket.h"
- #include "usock.h"
- #include "ax25.h"
- #include "smtp.h"
-
- /*
- #define MBDEBUG
- */
-
- static struct mbx *Mbox[NUMMBX] ;
- int Ax25mbox ;
-
- static char Mbbanner[] = "[NET-$]\rWelcome to the %s TCP/IP Mailbox\r%s";
- static char Mbmenu[] = "(C)hat, (S)end, (B)ye >\r" ;
-
- static int donothing __ARGS((int argc,char *argv[],void *p));
- static int dosend __ARGS((int argc,char *argv[],void *p));
- static int dochat __ARGS((int argc,char *argv[],void *p));
- static void domboxdisplay __ARGS((void));
- static int dosid __ARGS((int argc,char *argv[],void *p));
- static int dorevfwd __ARGS((int argc,char *argv[],void *p));
- static struct mbx *newmbx __ARGS((void));
- static int mbx_parse __ARGS((struct mbx *m));
- static void mbx_getname __ARGS((struct mbx *m));
- static int dobye __ARGS((int argc,char *argv[],void *p));
- static int mbx_to __ARGS((int argc,char *argv[],void *p));
- static int mbx_data __ARGS((struct mbx *m));
-
- static struct cmds Mbcmds[] = {
- "", donothing, 0, 0, NULLCHAR,
- "s", dosend, 0, 0, NULLCHAR,
- "send", dosend, 0, 0, NULLCHAR,
- "chat", dochat, 0, 0, NULLCHAR,
- "bye", dobye, 0, 0, NULLCHAR,
- "[", dosid, 0, 0, NULLCHAR,
- "f>", dorevfwd, 0, 0, NULLCHAR,
- NULLCHAR, NULLFP, 0, 0, NULLCHAR,
- };
-
- int
- dombox(argc, argv,p)
- int argc ;
- char *argv[] ;
- void *p;
- {
- setbool(&Ax25mbox,"AX25 mailbox",argc,argv);
- if (argc < 2)
- domboxdisplay() ;
- return 0;
- }
-
- static void
- domboxdisplay()
- {
- int i ;
- struct mbx *m ;
- static char *states[] = {"NONE","CMD","SUBJ","DATA"} ;
-
- printf("User State Type S#\n");
-
- for (i = 0 ; i < NUMMBX ; i++)
- if ((m = Mbox[i]) != NULLMBX) {
- printf("%-10s %-4s %-7s %-3u\n",m->name,
- states[m->state],Sestypes[m->type],m->user);
- }
- }
-
- static struct mbx *
- newmbx()
- {
- int i ;
- struct mbx *m ;
-
- for (i = 0 ; i < NUMMBX ; i++)
- if (Mbox[i] == NULLMBX) {
- if ((m = Mbox[i] = (struct mbx *)calloc(1,sizeof(struct mbx)))
- == NULLMBX)
- return NULLMBX ;
- m->mbnum = i ;
- return m ;
- }
-
- /* If we get here, there are no free mailbox sessions */
-
- return NULLMBX ;
- }
-
- /* Incoming mailbox session */
-
- void
- mbx_incom(s,t,p)
- int s;
- void *t;
- void *p;
- {
- int type; /* type of session when invoking "chat" */
- int i;
- char buf[30];
- struct mbx *m ;
-
- type = (int)t;
- sockowner(s,Curproc); /* We own it now */
- sprintf(buf,"open %s MBOX",Sestypes[type]);
- log(s,buf);
- if ((m = newmbx()) == NULLMBX) {
- usprintf(s,"Too many mailbox sessions\r");
- close_s(s) ; /* no memory! */
- return ;
- }
- m->user = s;
- m->type = type;
- m->state = MBX_CMD ; /* start in command state */
- mbx_getname(m); /* get the name of the remote station */
-
- /* Now say hi */
- usprintf(s,Mbbanner,Hostname,Mbmenu);
- while (recvline(s,m->line,MBXLINE) != -1) {
- if (m->line[0] != '\n' && m->line[0] != '\r'){
- i = mbx_parse(m);
- if (i == -1)
- usprintf(s,"Huh?\r");
- if (i == 1)
- usprintf(s,"Bad syntax.\r");
- }
- usprintf(s,(m->sid & MBX_SID) ? ">\r" : Mbmenu);
- m->state = MBX_CMD;
- }
- free(m->to) ;
- free(m->tofrom) ;
- free(m->tomsgid) ;
- Mbox[m->mbnum] = NULLMBX ;
- free((char *)m) ;
- }
-
- /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
- They have to be treated specially since cmdparse() wants a space between
- the actual command and its arguments.
- "SP FOO" is converted to "s foo" and the second command letter is saved
- in m->stype. Longer commands like "SEND" are unaffected, except for
- commands starting with "[", i.e. the SID, since we don't know what it will
- look like.
- */
- static char twocmds[] = "slrn["; /* S,L,R,N are two-letter commands */
- static int
- mbx_parse(m)
- struct mbx *m;
- {
- char *cp;
- int i;
- /* Translate entire buffer to lower case */
- for (cp = m->line; *cp != '\0'; ++cp)
- if (isupper(*cp))
- *cp = tolower(*cp);
- for (cp = m->line;isspace(*cp);++cp) ;/* Skip any spaces at the begining */
- m->stype = ' ';
- if (*cp != '\0' && *(cp+1) != '\0')
- for(i=0; i<strlen(twocmds); ++i)
- if (*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
- || *cp == '[')) {
- if (islower(*(++cp)))
- m->stype = toupper(*cp); /* Save the second character */
- else m->stype = *cp;
- *cp = ' ';
- break;
- }
- return cmdparse(Mbcmds,m->line,(void *)m);
- }
-
- static void
- mbx_getname(m)
- struct mbx *m;
- {
- char *cp;
- union sp sp;
- char tmp[MAXSOCKSIZE];
- int len = MAXSOCKSIZE;
-
- getpeername(m->user,tmp,&len);
- /* This is one of the two parts of the mbox code that depends on the
- underlying protocol. We have to figure out the name of the
- calling station. This is only practical when AX.25 or NET/ROM
- is used. If we were using the mbox with TCP/IP one would
- rather have to login in a manner similar to ftp.
- */
- sp.p = tmp;
- switch(sp.sa->sa_family){
- case AF_NETROM:
- case AF_AX25:
- /* NETROM and AX25 socket address structures are "compatible" */
- pax25(m->name,&sp.ax->ax25_addr) ;
- cp = strchr(m->name,'-') ;
- if (cp != NULLCHAR) /* get rid of SSID */
- *cp = '\0' ;
- /* case AF_INET: We need a gethostbyaddr() or login procedure first */
- }
- }
-
- static int
- dobye(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct mbx *m;
-
- m = (struct mbx *)p;
- close_s(m->user);
- return 0;
- }
- static int
- dochat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct mbx *m;
- struct proc *pp;
-
- m = (struct mbx *)p;
- pp = newproc("in_chat",2048,axnrhandle,m->user,(void *)m->type,NULL);
- pwait(pp);
- /* It returns only after a disconnect */
- return 0;
- }
-
- /* Called every time a blank line is received. */
- static int
- donothing(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return 0;
- }
-
- static int
- dosend(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- int s;
- char *host,fullfrom[80];
- struct mbx *m;
-
- m = (struct mbx *)p;
- s = m->user;
- if (mbx_to(argc,argv,m) == -1) {
- if (m->sid & MBX_SID)
- usprintf(s,"NO - syntax error\r") ;
- else {
- usprintf(s,"S command syntax error - format is:\r");
- usprintf(s," S name [@ host] [< from_addr] [$bulletin_id]\r");
- }
- return 0;
- }
- if (validate_address(m->to) == 0){
- if (m->sid & MBX_SID)
- usprintf(s, "NO - bad address\r");
- else
- usprintf(s, "Bad user or host name\r");
- /* We don't free any buffers here. They are freed upon the next
- * call to mbx_to() or to dobye()
- */
- return 0;
- }
- m->state = MBX_SUBJ ;
- usprintf(s, (m->sid & MBX_SID) ? "OK\r" : "Subject:\r");
- if (recvline(s,m->line,MBXLINE) == -1)
- return 0;
- rip(m->line);
- if (mbx_data(m) == -1) {
- usprintf(s,"Can't create temp file for mail\r") ;
- return 0 ;
- }
- m->state = MBX_DATA ;
- if ((m->sid & MBX_SID) == 0)
- usprintf(s,
- "Enter message. Terminate with /EX or ^Z in first column:\r");
-
- while (recvline(s,m->line,MBXLINE) != -1) {
- rip(m->line);
- if (m->line[0] == 0x1a ||
- strcmp(m->line, "/ex") == 0 ||
- strcmp(m->line, "/EX") == 0) {
- if ((host = strchr(m->to,'@')) == NULLCHAR)
- host = Hostname ; /* use our hostname */
- else
- host++ ; /* use the host part of address */
-
- /* make up full from name for work file */
- (void)sprintf(fullfrom,"%s@%s",m->name,Hostname) ;
- fseek(m->tfile,0L,0) ; /* reset to beginning */
- if (queuejob(m->tfile,host,m->to,fullfrom) != 0)
- usprintf(s, "Couldn't queue message for delivery\r");
- break;
- } else
- fprintf(m->tfile,"%s\n",m->line) ; /* not done yet! */
- }
- fclose(m->tfile) ;
- return 0 ;
- }
-
- static int
- dosid(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct mbx *m;
-
- m = (struct mbx *)p;
- if (argc == 1)
- return 1;
- if (argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
- return 1;
- m->sid = MBX_SID ;
- /* Now check to see if this is an RLI board.
- * As usual, Hank does it a bit differently from
- * the rest of the world.
- */
- if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
- m->sid |= MBX_SID_RLI ;
- return 0;
- }
-
- static int
- dorevfwd(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
-
- {
- struct mbx *m;
-
- m = (struct mbx *)p;
- if (m->sid & MBX_SID) {
- /* RLI BBS' expect us to disconnect if we
- * have no mail for them, which of course
- * we don't, being rather haughty about our
- * protocol superiority.
- */
- if (m->sid & MBX_SID_RLI)
- dobye(0,NULL,m) ;
- return 0;
- }
- return -1;
- }
-
- /* States for send line parser state machine */
-
- #define LOOK_FOR_USER 2
- #define IN_USER 3
- #define AFTER_USER 4
- #define LOOK_FOR_HOST 5
- #define IN_HOST 6
- #define AFTER_HOST 7
- #define LOOK_FOR_FROM 8
- #define IN_FROM 9
- #define AFTER_FROM 10
- #define LOOK_FOR_MSGID 11
- #define IN_MSGID 12
- #define FINAL_STATE 13
- #define ERROR_STATE 14
-
- /* Prepare the addressee. If the address is bad, return -1, otherwise
- * return 0
- */
- static int
- mbx_to(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register char *cp;
- int state, i ;
- char *user, *host, *from, *msgid ;
- int userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0 ;
- struct mbx *m ;
-
- m = (struct mbx *)p;
- /* Free anything that might be allocated
- * since the last call to mbx_to()
- */
- free(m->to) ;
- m->to = NULLCHAR ;
- free(m->tofrom) ;
- m->tofrom = NULLCHAR ;
- free(m->tomsgid) ;
- m->tomsgid = NULLCHAR ;
-
- if (argc == 1)
- return -1;
- i = 1;
- cp = argv[i];
- state = LOOK_FOR_USER ;
- while (state < FINAL_STATE) {
- #ifdef MBDEBUG
- printf("State is %d, char is %c\n", state, *cp) ;
- #endif
- switch (state) {
- case LOOK_FOR_USER:
- if (*cp == '@' || *cp == '<' || *cp == '$')
- state = ERROR_STATE ; /* no user */
- else {
- user = cp ; /* point at start */
- userlen++ ; /* start counting */
- state = IN_USER ;
- }
- break ;
- case IN_USER:
- switch (*cp) {
- case '\0':
- state = AFTER_USER ; /* done with username */
- break ;
- case '@':
- state = LOOK_FOR_HOST ; /* hostname should follow */
- break ;
- case '<':
- state = LOOK_FOR_FROM ; /* from name should follow */
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* message id should follow */
- break ;
- default:
- userlen++ ; /* part of username */
- }
- break ;
- case AFTER_USER:
- switch (*cp) {
- case '@':
- state = LOOK_FOR_HOST ; /* hostname follows */
- break ;
- case '<':
- state = LOOK_FOR_FROM ; /* fromname follows */
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* message id follows */
- break ;
- default:
- state = ERROR_STATE ;
- }
- break ;
- case LOOK_FOR_HOST:
- if (*cp == '@' || *cp == '<' || *cp == '$') {
- state = ERROR_STATE;
- break;
- }
- if (*cp == '\0')
- break;
- host = cp ;
- hostlen++ ;
- state = IN_HOST ;
- break ;
- case IN_HOST:
- switch (*cp) {
- case '\0':
- state = AFTER_HOST ; /* found user@host */
- break ;
- case '@':
- state = ERROR_STATE ; /* user@host@? */
- break ;
- case '<':
- state = LOOK_FOR_FROM ; /* fromname follows */
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* message id follows */
- break ;
- default:
- hostlen++ ;
- }
- break ;
- case AFTER_HOST:
- switch (*cp) {
- case '@':
- state = ERROR_STATE ; /* user@host @ */
- break ;
- case '<':
- state = LOOK_FOR_FROM ; /* user@host < */
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* user@host $ */
- break ;
- default:
- state = ERROR_STATE ; /* user@host foo */
- }
- break ;
- case LOOK_FOR_FROM:
- if (*cp == '@' || *cp == '<' || *cp == '$') {
- state = ERROR_STATE;
- break;
- }
- if (*cp == '\0')
- break;
- from = cp ;
- fromlen++ ;
- state = IN_FROM ;
- break ;
- case IN_FROM:
- switch (*cp) {
- case '\0':
- state = AFTER_FROM ; /* user@host <foo */
- break ;
- case '<':
- state = ERROR_STATE ; /* user@host <foo< */
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* message id follows */
- break ;
- default:
- fromlen++ ;
- }
- break ;
- case AFTER_FROM:
- switch (*cp) {
- case '@': /* user@host <foo @ */
- case '<': /* user@host <foo < */
- state = ERROR_STATE ;
- break ;
- case '$':
- state = LOOK_FOR_MSGID ; /* user@host <foo $ */
- break ;
- default:
- state = ERROR_STATE ; /* user@host foo */
- }
- break ;
- case LOOK_FOR_MSGID:
- if (*cp == '\0')
- break;
- msgid = cp ;
- msgidlen++ ;
- state = IN_MSGID ;
- break ;
- case IN_MSGID:
- if (*cp == '\0')
- state = FINAL_STATE ;
- else
- msgidlen++ ;
- break ;
- default:
- /* what are we doing in this state? */
- state = ERROR_STATE ;
- }
- if (*(cp) == '\0') {
- ++i;
- if (i < argc)
- cp = argv[i];
- else break;
- }
- else ++cp;
- }
- if (state == ERROR_STATE || state == LOOK_FOR_HOST
- || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
- return -1 ; /* syntax error */
-
- if ((m->to = malloc(userlen + hostlen + 2)) == NULLCHAR)
- return -1 ; /* no room for to address */
-
- strncpy(m->to, user, userlen) ;
- m->to[userlen] = '\0' ;
-
- if (hostlen) {
- m->to[userlen] = '@' ;
- strncpy(m->to + userlen + 1, host, hostlen) ;
- m->to[userlen + hostlen + 1] = '\0' ;
- }
- if (fromlen) {
- if ((m->tofrom = malloc(fromlen + 1)) == NULLCHAR) {
- free(m->to) ;
- m->to = NULLCHAR ;
- return -1 ;
- }
- strncpy(m->tofrom, from, fromlen) ;
- m->tofrom[fromlen] = '\0' ;
- }
- if (msgidlen) {
- if ((m->tomsgid = malloc(msgidlen + 1)) == NULLCHAR) {
- free(m->to) ;
- m->to = NULLCHAR ;
- free(m->tofrom) ;
- m->tofrom = NULLCHAR ;
- return -1 ;
- }
- strncpy(m->tomsgid, msgid, msgidlen) ;
- m->tomsgid[msgidlen] = '\0' ;
- }
- return 0 ;
- }
-
- /* This opens the data file and writes the mail header into it.
- * Returns 0 if OK, and -1 if not.
- */
- static int
- mbx_data(m)
- struct mbx *m ;
- {
- time_t t, time() ;
- char *ptime() ;
- extern FILE *tmpfile();
- extern long get_msgid() ;
-
- if ((m->tfile = tmpfile()) == NULLFILE)
- return -1 ;
- time(&t) ;
- fprintf(m->tfile,"Date: %s",ptime(&t)) ;
- if (m->tomsgid)
- fprintf(m->tfile,"Message-Id: <%s@%s.bbs>\n", m->tomsgid, m->name) ;
- else
- fprintf(m->tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
- fprintf(m->tfile,"From: %s%%%s.bbs@%s\n",
- m->tofrom ? m->tofrom : m->name, m->name, Hostname) ;
- fprintf(m->tfile,"To: %s\n",m->to) ;
- fprintf(m->tfile,"Subject: %s\n",m->line) ;
- if (!isspace(m->stype))
- fprintf(m->tfile,"X-BBS-Msg-Type: %c\n", m->stype) ;
- fprintf(m->tfile,"\n") ;
-
- return 0 ;
- }
-
-